﻿using Api.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;

namespace Api.DAL
{
    public class BaseDAL<T> where T : BaseModel
    {
        public static BaseDAL<T> Current
        {
            get
            {
                var m = CallContext.GetData("basedal") as BaseDAL<T>;
                if (m == null)
                {
                    m = new BaseDAL<T>();
                    CallContext.SetData("basedal", m);
                }
                return m;
            }
        }

        protected Db db = Db.Current;
        protected DbSet<T> dbSet;
        public BaseDAL()
        {
            dbSet = db.Set<T>();
        }
        public virtual int Insert(T model)
        {
            dbSet.Add(model);
            return db.SaveChanges();
        }
        public virtual int Delete(object col)
        {
            T entityToDelete = dbSet.Find(col);
            if (entityToDelete != null)
                dbSet.Remove(entityToDelete);
            return db.SaveChanges();
        }
        public virtual int Update(T entityToUpdate)
        {
            db.Entry(entityToUpdate).State = EntityState.Modified;
            return db.SaveChanges();
        }



        public int UpdateIgnore(Expression<Func<T, object>> propertyExpression, params T[] entities)
        {
            return db.UpdateIgnore(propertyExpression, entities);
        }
        /// <summary>
        /// 實現對像部分屬性的更新，newModel必須時匿名對象
        /// </summary>
        /// <param name="originalEntity"></param>
        /// <param name="newEntity">newModel必須時匿名對象（這樣是為了保證不加入多餘的屬性）</param>
        /// <returns></returns>
        public int Update(T originalEntity, object newEntity)
        {
            var entry = db.Entry(originalEntity);
            if (entry.State != EntityState.Unchanged)
                entry.State = EntityState.Unchanged;
            entry.CurrentValues.SetValues(newEntity);
            return db.SaveChanges();
        }
        public virtual void InsertAll(IEnumerable<T> list)
        {
            dbSet.AddRange(list);
            db.SaveChanges();
        }
        public virtual void UpdateAll(IEnumerable<T> list)
        {
            foreach (var item in list)
            {
                var entity = dbSet.Attach(item);
                db.Entry(item).State = EntityState.Modified;
            }
            db.SaveChanges();
        }
        public virtual void DeleteList(IEnumerable<T> list)
        {
            dbSet.RemoveRange(list);
            db.SaveChanges();
        }
        public virtual void DeleteList(Expression<Func<T, bool>> predicate = null)
        {

            var list = GetList(predicate);
            dbSet.RemoveRange(list);
            db.SaveChanges();
        }
        public T GetModel(Expression<Func<T, bool>> predicate = null)
        {
            return dbSet.FirstOrDefault(predicate);
        }
        public virtual IEnumerable<T> GetList(Expression<Func<T, bool>> predicate = null, bool notrack = false)
        {
            if (predicate != null)
            {
                if (notrack)
                {
                    return dbSet.Where(predicate).AsNoTracking().ToList().AsQueryable();
                }
                return dbSet.Where(predicate).ToList();
            }
            return dbSet.ToList();
        }
    }
}
